﻿using System;
using System.Collections.Generic;
using FixMath;
using UniFramework.Actor;
using UniFramework.Battle;
using UniFramework.Skill;
using UnityEngine;

namespace UniFramework.Buff
{
	public class BuffSystem : MonoBehaviour
	{
		private List<BuffObj> _buffList;
		private LogicActor _actor;
		private bool _isInit = false;
		public bool IsInit => _isInit;
		public List<BuffObj> BuffList => _buffList;
		private List<string> _needRemoveBuffList;

		public void OnInit(LogicActor actor)
		{
			_buffList = new();
			_needRemoveBuffList = new List<string>();
			_actor = actor;
			_isInit = true;
		}

		public void OnDispose()
		{
			_needRemoveBuffList?.Clear();
			_needRemoveBuffList = null;
			_buffList.Clear();
			_buffList = null;
			_isInit = false;
		}

		public void OnLogicFrameUpdate()
		{
			if (!_isInit) UniLogger.Warning("BuffSystem Is Not Init");
			if (_buffList.Count <= 0) return;
			FixInt timePassed = LogicFrameConfig.logicFrameIntervalFixInt;
			List<BuffObj> needRemoveBuffList = new List<BuffObj>();
			foreach (var buff in _buffList)
			{
				if (!buff.permanent) buff.duration -= timePassed;
				buff.timeElapsed += timePassed;

				if (buff.buffConfig.tickTime > 0 && buff.buffConfig.onTick != null)
				{
					//每tick多少时间去执行一次
					if (buff.timeElapsed % buff.buffConfig.tickTime == 0)
					{
						buff.buffConfig.onTick?.Invoke(buff);
						++buff.tickedCnt;
					}
				}

				if (!buff.permanent && (buff.duration <= 0 || buff.stack <= 0))
				{
					buff.buffConfig.onRemoved?.Invoke(buff);
					needRemoveBuffList.Add(buff);
				}
			}

			if (needRemoveBuffList.Count > 0)
			{
				foreach (var removeBuff in needRemoveBuffList)
				{
					_buffList.Remove(removeBuff);
				}
			}

			needRemoveBuffList.Clear();
			needRemoveBuffList = null;

			if (_needRemoveBuffList.Count > 0)
			{
				foreach (var needRemoveBuff in _needRemoveBuffList)
				{
					DoRemoveBuff(needRemoveBuff);
				}
			}

			_needRemoveBuffList.Clear();
		}


		/// <summary>
		/// 基于id得到buff
		/// </summary>
		/// <param name="id"></param>
		/// <param name="release"></param>
		/// <returns></returns>
		public BuffObj GetBuffListById(string id, List<LogicActor> release = null)
		{
			for (int i = 0; i < this._buffList.Count; i++)
			{
				if (_buffList[i].buffConfig.id == id &&
				    (release == null || release.Count <= 0 || release.Contains(_buffList[i].release) == true))
				{
					return _buffList[i];
				}
			}

			return null;
		}

		/// <summary>
		/// 增删Buff，没有删除buff的逻辑
		/// </summary>
		/// <param name="buffInfo"></param>
		public void AddBuff(AddBuffInfo buffInfo)
		{
			List<LogicActor> bCaster = new List<LogicActor>();
			if (buffInfo.release) bCaster.Add(buffInfo.release);
			BuffObj findBuff = GetBuffListById(buffInfo.buffConfig.id, bCaster);
			int modStack = buffInfo.addStack;
			bool toRemove = false;
			BuffObj toAddBuff = null;
			if (findBuff != null)
			{
				//已经有当前Buff
				findBuff.buffParam = new Dictionary<string, object>();
				if (buffInfo.buffParam != null)
				{
					foreach (KeyValuePair<string, object> kv in buffInfo.buffParam)
					{
						findBuff.buffParam[kv.Key] = kv.Value;
					}
				}

				findBuff.duration = (buffInfo.durationSetTo == true)
					? buffInfo.duration
					: (buffInfo.duration + findBuff.duration);
				modStack = Math.Min(findBuff.buffConfig.maxStack, buffInfo.addStack + findBuff.stack);
				findBuff.stack = modStack;
				findBuff.permanent = buffInfo.permanent;
				toAddBuff = findBuff;
				toRemove = findBuff.stack <= 0;
			}
			else
			{
				//新建
				toAddBuff = new BuffObj(buffInfo.buffConfig, buffInfo.release, _actor, buffInfo.duration,
					buffInfo.addStack, buffInfo.permanent, buffInfo.buffParam);
				_buffList.Add(toAddBuff);
				_buffList.Sort((a, b) => a.buffConfig.priority.CompareTo(b.buffConfig.priority));
			}

			if (toRemove == false && buffInfo.buffConfig.onOccur != null)
			{
				buffInfo.buffConfig.onOccur(toAddBuff, modStack);
			}
		}

		/// <summary>
		/// 当前帧立即移除Buff
		/// </summary>
		/// <param name="id"></param>
		public void RemoveBuffImmediately(string id)
		{
			_needRemoveBuffList.Add(id);
		}

		private void DoRemoveBuff(string id)
		{
			foreach (var buff in _buffList)
			{
				if (buff.buffConfig.id == id)
				{
					_buffList.Remove(buff);
					buff.buffConfig.onRemoved?.Invoke(buff);
					break;
				}
			}
		}
	}
}